package opengles;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.opengl.GLES20;
import android.opengl.GLES30;
import android.opengl.GLSurfaceView;
import android.os.Environment;
import android.util.Log;

import com.scu.freehyan.pbojni.GLESJni;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import Camera.CameraEngine;

/**
 * Created by freehyan on 9/7/2016.
 */
public class GLESRenderer extends GLSurfaceView implements GLSurfaceView.Renderer{
    private CameraEngine mCamera;
    private SurfaceTexture mSurface;
    private FBO mFBO;
    private int[] mFBOColorTex0;
    private int[] mFBOColorTex1;
    private PBO mPBO;

    private CameraFBOPass mCameraPass;
    private PrimaryPass mPrimaryPass;
    private Context mActivityContext;

    private final int mFBOWidth = 1080;
    private final int mFBOHeight = 1845;
    private int mPhoneWidth;
    private int mPhoneHeight;
    private int mCameraTexture;

    public GLESRenderer(Context context, CameraEngine camera)
    {
        super(context);
        mActivityContext = context;
        mCamera = camera;
        setEGLContextClientVersion(2);
        setRenderer(this);
    }

    static int t = 0;
    @Override
    public void onDrawFrame(GL10 gl) {
        float[] mtx = new float[16];
        mSurface.updateTexImage();
        mSurface.getTransformMatrix(mtx);

        mFBO.openFBO();
        GLES20.glViewport(0, 0, mFBOWidth, mFBOHeight);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
        mCameraPass.render();

        t++;
        if (t== 10)
        {
            int width = mFBOWidth, height = mFBOHeight;
            //默认缓存区使用方式, PBO 读取前表面，21 ms
//            int PBOId = mPBO.getPBOId();
//            long start = System.currentTimeMillis();
//            GLES30.glReadBuffer(GLES30.GL_FRONT);
//            GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, PBOId);
//            Log.e("GLES", "before glReadPixels: " + (System.currentTimeMillis() - start));
//            GLESJni.glReadPixelsPBOJNI(0, 0, mFBOWidth, mFBOHeight, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, 0);
//            ByteBuffer  PBOBuffer = (ByteBuffer )GLES30.glMapBufferRange(GLES30.GL_PIXEL_PACK_BUFFER, 0, mFBOWidth*mFBOHeight*4, GLES30.GL_MAP_READ_BIT);
//            Log.e("GLES", "after glReadPixels: " + (System.currentTimeMillis() - start));
//            GLES30.glUnmapBuffer(GLES30.GL_PIXEL_PACK_BUFFER);
//            GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0);
//            saveRgb2Bitmap(PBOBuffer, "GLES", width, height);

           // ByteBuffer PixelsBuffer = ByteBuffer.allocateDirect(width * height * 4).order(ByteOrder.nativeOrder());
           // byte[] pboArray = new byte[width * height * 4];

            //直接读取屏幕纹理，300ms
//            long start = System.currentTimeMillis();
//            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mFBOColorTex0[0]);
//            Log.e("GLES", "before glReadPixels: " + (System.currentTimeMillis() - start));
//            GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, PixelsBuffer);
//            Log.e("GLES", "after glReadPixels: " + (System.currentTimeMillis() - start));
//            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
//            saveRgb2Bitmap(PixelsBuffer, "GLES", width, height);

            long start = System.currentTimeMillis();
            //读取FBO texture, PBO 44MS
            int PBOId = mPBO.getPBOId();
            GLES30.glReadBuffer(GLES30.GL_COLOR_ATTACHMENT1);
            GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, PBOId);
            Log.e("GLES", "before glReadPixels: " + (System.currentTimeMillis() - start));
            GLESJni.glReadPixelsPBOJNI(0, 0, mFBOWidth, mFBOHeight, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, 0);
            ByteBuffer  PBOBuffer = (ByteBuffer )GLES30.glMapBufferRange(GLES30.GL_PIXEL_PACK_BUFFER, 0, mFBOWidth*mFBOHeight*4, GLES30.GL_MAP_READ_BIT);
            Log.e("GLES", "after glReadPixels: " + (System.currentTimeMillis() - start));
            GLES30.glUnmapBuffer(GLES30.GL_PIXEL_PACK_BUFFER);
            GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0);
            saveRgb2Bitmap(PBOBuffer, "GLES", width, height);
    }
        mFBO.closeFBO();

       drawScreenQuad();
    }

    private void drawScreenQuad(){
        GLES20.glViewport(0, 0, mPhoneWidth, mPhoneHeight);
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        mFBO.bindForReadTargetTex(GLES20.GL_TEXTURE0, mFBOColorTex0[0]);
        mPrimaryPass.render();
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
        mPhoneWidth = width;
        mPhoneHeight = height;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        mCameraTexture = Texture.createCameraTexture();
        mCameraPass = new CameraFBOPass(mCameraTexture, mActivityContext);
        mSurface = new SurfaceTexture(mCameraTexture);
        mCamera.startCamera(mSurface);

        initBufferObjects();
        mCameraPass = new CameraFBOPass(mCameraTexture, mActivityContext);
        mPrimaryPass = new PrimaryPass(mActivityContext);
    }

    private void initBufferObjects(){
        mFBO = new FBO();
        mFBOColorTex0 = new int[1];
        mFBOColorTex1 = new int[1];
        mFBO.initFBO(mFBOWidth, mFBOHeight);
        mFBO.mountTexture(mFBOColorTex0, 0);
        mFBO.mountTexture(mFBOColorTex1, 1);
        mFBO.attachTex2FBO();

        mPBO = new PBO();
        mPBO.createPBO(mFBOWidth * mFBOHeight * 4);
    }

    static void saveRgb2Bitmap(Buffer buf, String filename, int width, int height) {
        Log.d("GLES", "Creating " + filename);
        File extDir = Environment.getExternalStoragePublicDirectory("Pictures");
        File fullFilename = new File(extDir, filename + ".png");

        BufferedOutputStream bos = null;
        try {
            bos = new BufferedOutputStream(new FileOutputStream(fullFilename));
            Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            bmp.copyPixelsFromBuffer(buf);
            bmp.compress(Bitmap.CompressFormat.PNG, 90, bos);
            bmp.recycle();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
